package com.syn.michat.im.service.impl;

import com.alibaba.fastjson.JSON;
import com.syn.michat.constant.ErrorContants;
import com.syn.michat.constant.FriendContants;
import com.syn.michat.constant.MessageContants;
import com.syn.michat.im.WebSocketSessionManager;
import com.syn.michat.im.model.AckEntity;
import com.syn.michat.im.model.MessageEntity;
import com.syn.michat.im.model.Package;
import com.syn.michat.im.service.MessageService;
import com.syn.michat.im.service.PackageService;
import com.syn.michat.pojo.Friend;
import com.syn.michat.pojo.OfflineMsg;
import com.syn.michat.pojo.User;
import com.syn.michat.service.FriendsService;
import com.syn.michat.util.BlowfishUtil;
import com.syn.michat.util.TokenUtil;
import com.syn.michat.util.exception.ClientException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.websocket.Session;
import java.io.IOException;
import java.util.List;

@Service
public class PackageServiceImpl implements PackageService {

    @Autowired
    private MessageService messageService;
    @Autowired
    private FriendsService friendsService;

    @Override
    public void resPackageHandler(String packageStr, Session session) throws Exception {
        Package aPackage = JSON.parseObject(packageStr, Package.class);
        User user = verifyToken(aPackage.getToken(), session);
        if (user == null) { return; }

        String content = aPackage.getData();
        if (content != null) {
            content = BlowfishUtil.decrypt(content);
        }

        if (aPackage.getType().equals(Package.PACKAGE_TYPE_MESSAGE)) {
            MessageEntity msg = JSON.parseObject(content, MessageEntity.class);
            String receiverId = msg.getReceiver().getUserId();
            Friend friend = friendsService.findFriend(receiverId, user.getUserId());

            // 判断对方与自己是否还是好友关系
            if (friend.getStatus() == FriendContants.FRIEND) {
                Session receiverSession = WebSocketSessionManager.sessionMap.get(receiverId);
                // 用户离线，保存消息，等待用户上线时发送离线消息
                if (receiverSession == null) {
                    String aPackageStr = JSON.toJSONString(aPackage);
                    messageService.saveOfflineMsg(aPackageStr, msg);
                } else {
                    receiverSession.getBasicRemote().sendText(JSON.toJSONString(aPackage));
                }
            } else { // 不是好友返回ACK
                AckEntity ack = new AckEntity();
                ack.setUuid(msg.getUuid());
                ack.setType(Package.PACKAGE_TYPE_MESSAGE);
                ack.setStatus(AckEntity.ACK_ENTRY_STATUS_500);
                ack.setCode(AckEntity.ACK_ENTRY_CODE_STRANGER);
                sendPackage(buildAckPackage(ack), session);
            }
        } else if (aPackage.getType().equals(Package.PACKAGE_TYPE_AUTH)) {
            WebSocketSessionManager.add(user.getUserId(), session);

            AckEntity ack = new AckEntity();
            ack.setType(Package.PACKAGE_TYPE_AUTH);
            ack.setStatus(AckEntity.ACK_ENTRY_STATUS_200);
            // 发送Auth的Ack
            sendPackage(buildAckPackage(ack), session);
            // 发送离线时未接收消息
            sendOfflineMsg(user.getUserId());
        }
    }

    @Override
    public void sendPackage(Package aPackage, Session session) throws Exception {
        // 用户离线，保存消息，等待用户上线时发送离线消息
        if (session == null) {
            String aPackageStr = JSON.toJSONString(aPackage);
            String packageData = BlowfishUtil.decrypt(aPackage.getData());
            MessageEntity msg = JSON.parseObject(packageData, MessageEntity.class);
            messageService.saveOfflineMsg(aPackageStr, msg);
        } else {
            session.getBasicRemote().sendText(JSON.toJSONString(aPackage));
        }
    }

    private void sendOfflineMsg(String userId) throws ClientException {
        Session session = WebSocketSessionManager.sessionMap.get(userId);
        List<OfflineMsg> list = messageService.findByReceiverId(userId, MessageContants.OFFLINE_MESSAGE_NOT_SENT);
        for (OfflineMsg msg : list) {
            try {
                session.getBasicRemote().sendText(msg.getPackageStr());
                messageService.updateStatus(msg.getId(), MessageContants.OFFLINE_MESSAGE_HAS_BEEN_SENT);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    /**
    * @Description: 验证token
    * @Params: [token, session]
    * @return: java.lang.Boolean
    * @Author: 申铭
    * @Date: 2021/12/30
    */
    private User verifyToken(String token, Session session) throws Exception {
        TokenUtil util = new TokenUtil();
        try {
            return util.verifyToken(token);
        } catch (ClientException e) {
            String code = e.getCode();

            AckEntity ack = new AckEntity();
            ack.setType(Package.PACKAGE_TYPE_AUTH);
            ack.setStatus(AckEntity.ACK_ENTRY_STATUS_500);
            ack.setCode(code);

            if (code == ErrorContants.ACCESSTOKEN_INVALID) {
                ack.setContent("token已过期");
            } else if (code == ErrorContants.ACCESSTOKEN_ILLEGAL) {
                ack.setContent("非法的token");
            }

            sendPackage(buildAckPackage(ack), session);
            return null;
        }
    }

    private Package buildAckPackage(AckEntity ack) throws Exception {
        Package aPackage = new Package();
        aPackage.setType(Package.PACKAGE_TYPE_ACK);
        aPackage.setData(BlowfishUtil.encrypt(JSON.toJSONString(ack)));
        return aPackage;
    }
}
